/**
 * localeIconsTreeView.js
 * Copyright (C) 2007-2011 Tommi Rautava
 * 
 * This file is part of Popmungo.
 *
 * Popmungo is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Popmungo is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.	If not, see <http://www.gnu.org/licenses/>.
*/

/**
 * org.mozdev.popmungo.classes.LocaleIconsTreeView
 *
 * The code is based on an example by Neil Rashbrook presented at
 * http://www.xulplanet.com/tutorials/xulqa/q_treebview.html
 */

org.mozdev.popmungo.classes.LocaleIconsTreeView = function LocaleIconsTreeView() {};

org.mozdev.popmungo.classes.LocaleIconsTreeView.prototype = {

	selection: null,

	getRowProperties: function getRowProperties(row, props) {
		// void
	},

	getCellProperties: function getCellProperties(row, col, props) {
    	if (col.id == "localeIcon") {
			var atomService = Components.classes["@mozilla.org/atom-service;1"].
				getService(Components.interfaces.nsIAtomService);
			props.AppendElement(atomService.getAtom("localeIcon"));
    	}
	},

	getColumnProperties: function getColumnProperties(col, elem, props) {
		// void
	},

	isContainer: function isContainer(row) {
		if (row in this._subtreeItems) {
			return this._subtreeItems[row]._childItems.length;
		}

		throw 0x8000FFFF; // Components.results.NS_ERROR_UNEXPECTED;
	},

	isContainerOpen: function isContainerOpen(row) {
		return this._subtreeItems[row]._open;
	},

	isContainerEmpty: function isContainerEmpty(row) {
		return false;
	},

	isSeparator: function isSeparator(row) {
		return false;
	},

	isSorted: function isSorted() {
		return true;
	},

	canDropOn: function canDropOn(row) {
		return false;
	},

	canDropBeforeAfter: function canDropBeforeAfter(row, before) { 
		return false;
	},

	drop: function drop(row, orientation) {
		// void
	},

	getParentIndex: function getParentIndex(row) {
		return this.getIndexOfItem(this._subtreeItems[row]._parentItem);
	},

	hasNextSibling: function hasNextSibling(row, after) {
		return this._subtreeItems[row]._hasNext;
	},

	getLevel: function getLevel(row) {
		if (row in this._subtreeItems) {
			var level = 0;

			for (var item = this._subtreeItems[row]; item._parentItem != this; ++level) {
				item = item._parentItem;
			}

			return level;
		}

		throw 0x8000FFFF; // Components.results.NS_ERROR_UNEXPECTED;
	},

    getImageSrc: function getImageSrc(row, col) {
    	if (col.id == "localeIcon") {
    		return this._subtreeItems[row].localeIconUrl;
    	}
    	
    	return null;
    },


	getProgressMode : function getProgressMode(row, col) {
		return Components.interfaces.nsITreeView.PROGRESS_NONE;
	 },

	getCellValue: function getCellValue(row, col) {
		return null;
	},

	getCellText: function getCellText(row, col) {
		if (row in this._subtreeItems) {
			return this._subtreeItems[row][col.id].toString();
		}

		throw 0x8000FFFF; // Components.results.NS_ERROR_UNEXPECTED;
	},

	setTree: function setTree(treeBox) {
		this._treeBox = treeBox;

		if (!treeBox) {
			this.selection = null;
		}
	},

	cycleHeader: function cycleHeader(col, elem) {
		var colElem = col.element;
		var prevCol = document.getElementsByAttribute("sortActive", "true")[0];
		
		if (prevCol) {
			if (col.id == prevCol.id) {
				//org.mozdev.popmungo.logger.debug("Toggle sorting");
				
				// Toggle sort direction
				var sortDirection = colElem.getAttribute("sortDirection");
				sortDirection = (sortDirection == "ascending") ? "descending" : "ascending";
				
				this._subtreeItems.reverse();
				colElem.setAttribute("sortDirection", sortDirection);
			}
			else {
				//org.mozdev.popmungo.logger.debug("Switch sort column");

				prevCol.removeAttribute("sortActive");
				prevCol.removeAttribute("sortDirection");
				
				colElem.setAttribute("sortActive", true);
				colElem.setAttribute("sortDirection", "ascending");
				this._subtreeItems.sort(this._sorter[col.id]);
			}
		}
		else {
			org.mozdev.popmungo.logger.logError("Previous sorted column not found");
			
			colElem.setAttribute("sortActive", true);
			colElem.setAttribute("sortDirection", "ascending");			
			this._subtreeItems.sort(this._sorter[col.id]);
		}
		
	    this._treeBox.invalidate();
	},

	selectionChanged: function selectionChanged() {
		// void
	},

	cycleCell: function cycleCell(row, col) {
		// void
	},

	isEditable: function isEditable(row, col) { 
		return false; 
	},

	performAction: function performAction(action) {
		// void
	},

	performActionOnCell: function performActionOnCell(action, row, col) {
		// void
	},

	toggleOpenState: function toggleOpenState(row) {
		this._subtreeItems[row].toggleState();
	},

	/****************************************
	 * utility methods
	 ****************************************/
	getChildCount: function getChildCount() {
		return this._childItems.length;
	},

	getIndexOfItem: function getIndexOfItem(item) {
		if (!item) {
			throw 0x80004003; // Components.results.NS_ERROR_NULL_POINTER;
		}
		
		var row = -1;

		while (item != this) {
			var parent = item._parentItem;

			if (!parent) {
				throw 0x80004005; // Components.results.NS_ERROR_FAILURE;
			}
			
			for (var i = 0; (tmp = parent._childItems[i]) != item; ++i) {
				if (tmp._open) {
					row += tmp._subtreeItems.length;
				}
			}

			row += i + 1;
			item = parent;
		}

		return row;
	},

	getIndexOfChild: function getIndexOfChild(item) {
		if (!item) {
			throw 0x80004003; // Components.results.NS_ERROR_NULL_POINTER;
		}
		
		if (item._parentItem != this) {
			throw 0x80004005; // Components.results.NS_ERROR_FAILURE;
		}
		
		for (var i = 0; i < this._childItems.length; ++i) {
			if (this._childItems.length[i] == item) {
				return i;
			}
		}
		
		throw 0x80004005; // Components.results.NS_ERROR_FAILURE;
	},

	getItemAtIndex: function getItemAtIndex(row) {
		row = parseInt(row) || 0;
		
		if (row < 0 || row >= this._subtreeItems.length) {
			throw 0x80004005; // Components.results.NS_ERROR_FAILURE;
		}
		
		return this._subtreeItems[row];
	},

	getChildAtIndex: function getChildAtIndex(row) {
		row = parseInt(row) || 0;
		
		if (row < 0 || row >= this._childItems.length) {
			throw 0x80004005; // Components.results.NS_ERROR_FAILURE;
		}
		
		return this._childItems[row];
	},

	selectItem: function selectItem(item) {
		for (var parent = item.parentItem(); parent != this; parent = parent.parentItem()) {
			if (!parent) {
				throw 0x80004005; // Components.results.NS_ERROR_FAILURE;
			}
			else if (!parent.isOpen()) {
				parent.toggleState();
			}
		}

		var row = this.getIndexOfItem(item);
		this.selection.select(row);
		this._treeBox.ensureRowIsVisible(row);
	},

	invalidateRow: function invalidate() {
		var offset = -1;
		var parent;		

		for (var item = this; parent = item._parentItem; item = parent) {
			offset += item._getOffset();

			if (parent._treeBox) {
				parent._treeBox.invalidateRow(offset);
			}
			
			if (!parent._open) {
				break;
			}
		}
	},

	invalidatePrimaryCell: function invalidatePrimaryCell() {
		var offset = -1;
		var parent;

		for (var item = this; parent = item._parentItem; item = parent) {
			offset += item._getOffset();
			
			if (parent._treeBox) {
				parent._treeBox.invalidatePrimaryCell(offset);
			}
			
			if (!parent._open) {
				break;
			}
		}
	},

	invalidateCell: function invalidateCell(col) {
		var offset = -1;
		var parent;

		for (var item = this; parent = item._parentItem; item = parent) {
			offset += item._getOffset();
			
			if (parent._treeBox) {
				parent._treeBox.invalidateCell(offset);
			}
			
			if (!parent._open) {
				break;
			}
		}
	},

	toggleState: function toggleState() {
		this._open = !this._open;
		
		if (this._subtreeItems.length && this._parentItem) {
			if (this._open) {
				this._parentItem._itemExpanded(this._getOffset(), this._subtreeItems);
			}
			else {
				this._parentItem._itemCollapsed(this._getOffset(), this._subtreeItems.length);
			}
		}
	},

	removeItem: function removeItem(item) {
		if (!item) {
			throw 0x80004003; // Components.results.NS_ERROR_NULL_POINTER;
		}
		
		if (item._parentItem != this) {
			throw 0x80004005; // Components.results.NS_ERROR_FAILURE;
		}
		
		var change = 1;

		if (item._open) {
			change += item._subtreeItems.length;
		}
		
		var offset = 0;
		var tmpVar;

		for (var i = 0; (tmpVar = this._childItems[i]) != item; ++i) {
			if (tmpVar._open) {
				offset += tmpVar._subtreeItems.length;
			}
		}
		
		offset += i;
		this._childItems.splice(i, 1);

		if (i) {
			this._childItems[i - 1]._hasNext = item._hasNext;
		}
		
		item._hasNext = false;
		this._subtreeItems.splice(offset, change);

		if (this._treeBox) {
			this._treeBox.rowCountChanged(offset, -change);
		}
		
		if (this._parentItem) {
			this._parentItem._itemCollapsed(offset + this._getOffset(),
				this._open ? change : 0, this._childItems.length);
		}
		
		item._parentItem = null;
	},

	appendItem: function appendItem(item) {
		this.insertItem(item, this._childItems.length); 
	},

	insertItem: function insertItem(item, row) {
		if (!item) {
			throw 0x80004003; // Components.results.NS_ERROR_NULL_POINTER;
		}
		
		var length = this._childItems.length;
		row = parseInt(row) || 0;

		if (row < 0 || row > length) {
			throw 0x80004005; // Components.results.NS_ERROR_FAILURE;
		}

		if (item._parentItem) {
			item._parentItem.removeItem(item);
		}

		item._parentItem = this;
		var newItems = [item];
		var offset = row;

		if (!length) {
			this._childItems = newItems;
		}
		else {
			this._childItems.splice(row, 0, item);
			
			if (row == length) {
				this._childItems[length - 1]._hasNext = true;
				offset = this._subtreeItems.length;
			} else {
				item._hasNext = true;

				for (var i = 0; i < row; ++i) {
					if (this._childItems[i]._open) {
						offset += this._childItems[i]._subtreeItems.length;
					}
				}
			}
		}

		if (item._open) {
			newItems = newItems.concat(item._subtreeItems);
		}

		this._subtreeItems = this._subtreeItems.splice(0, offset).concat(newItems).concat(this._subtreeItems);

		if (this._treeBox) {
			this._treeBox.rowCountChanged(offset, newItems.length);
		}

		if (this._parentItem && (this._open || !length)) {
			this._parentItem._itemExpanded(offset + this._getOffset(), this._open ? newItems : [], length);
		}
	},

	parentItem: function parentItem() {
		return this._parentItem;
	},

	isOpen: function isOpen() {
		return this._open;
	},

	/****************************************
	 * helper methods
	 ****************************************/
	_itemExpanded: function _itemExpanded(offset, newItems, notwisty) {
		this._subtreeItems = this._subtreeItems.splice(0, offset).concat(newItems).concat(this._subtreeItems);

		if (this._treeBox) {
			this._treeBox.rowCountChanged(offset, newItems.length);

			if (offset && !notwisty) {
				this._treeBox.invalidatePrimaryCell(offset - 1);
			}
		}
		
		if (this._open && this._parentItem) {
			this._parentItem._itemExpanded(offset + this._getOffset(), newItems);
		}
	},

	_itemCollapsed: function _itemCollapsed(offset, change, notwisty) {
		this._subtreeItems.splice(offset, change);
		
		if (this._treeBox) {
			this._treeBox.rowCountChanged(offset, -change);
			
			if (offset && !notwisty) {
				this._treeBox.invalidatePrimaryCell(offset - 1);
			}
		}
		
		if (this._open && this._parentItem) {
			this._parentItem._itemCollapsed(offset + this._getOffset(), change);
		}
	},

	_getOffset: function _getOffset() {
		var offset = 1;
		var tmpVar;
		
		for (var i = 0; (tmpVar = this._parentItem._childItems[i]) != this; ++i) {
			if (tmpVar._open) {
				offset += tmpVar._subtreeItems.length;
			}
		}
		
		return offset + i;
	},
	
	_sorter: {
		localeTypeId:   function (a, b) { return (a.localeTypeId - b.localeTypeId); },
		localeIcon:     function (a, b) { return a.localeIconUrl.localeCompare(b.localeIconUrl); },
		localeTypeName: function (a, b) { return a.localeTypeName.localeCompare(b.localeTypeName); },
		localeIconUrl:  function (a, b) { return a.localeIconUrl.localeCompare(b.localeIconUrl); }
	},

	/****************************************
	 * default values
	 ****************************************/
	_parentItem: null,

	_hasNext: false,

	_childItems: [],

	_subtreeItems: [],

	_open: false,

	_treeBox: null,
	
	_atomService: null	
};

org.mozdev.popmungo.classes.LocaleIconsTreeView.prototype.__defineGetter__("rowCount", function() {
	return this._subtreeItems.length;
});

org.mozdev.popmungo.classes.LocaleIconsTreeItem = function LocaleIconsTreeItem(typeId, typeName, iconUrl) {
	this.localeTypeId = typeId;
	this.localeTypeName = typeName;
	this.localeIconUrl = iconUrl;
	this.localeIcon = "";	
};

org.mozdev.popmungo.classes.LocaleIconsTreeItem.prototype = new org.mozdev.popmungo.classes.LocaleIconsTreeView();

org.mozdev.popmungo.logger.log("org.mozdev.popmungo.classes.LocaleIconsTreeView loaded");

//EOF